package com.fowo.api.costAccounting.service.impl;

import com.fowo.api.costAccounting.entity.CostConfig;
import com.fowo.api.costAccounting.mapper.CommonCostingMapper;
import com.fowo.api.costAccounting.mapper.MonthlyCostReportMapper;
import com.fowo.api.costAccounting.model.bd.BdAccperiodmonthVo;
import com.fowo.api.costAccounting.model.cost.CostConfigProductVo;
import com.fowo.api.costAccounting.model.monthly.MonthlyCostReportItemVo;
import com.fowo.api.costAccounting.model.monthly.MonthlyVo;
import com.fowo.api.costAccounting.model.stock.StockInMonthlyVo;
import com.fowo.api.costAccounting.service.CostAccountingBusinessService;
import com.fowo.api.costAccounting.service.CostConfigProductService;
import com.fowo.api.costAccounting.service.CostConfigService;
import com.fowo.api.costAccounting.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class CostAccountingBusinessServiceImpl implements CostAccountingBusinessService {
    @Resource
    protected CostConfigService costConfigService;
    @Resource
    protected CostConfigProductService costConfigProductService;
    @Resource
    private MonthlyCostReportMapper monthlyCostReportMapper;
    @Resource
    private CommonCostingMapper commonCostingMapper;

    @Override
    public void updateMonthlyCostReport(String serialNumber) throws Exception {
        CostConfig costConfig = costConfigService.getSerialNumber(serialNumber);
       List<CostConfigProductVo> costConfigProductList= costConfigProductService.getByCostConfigId(costConfig.getId());
       if(costConfigProductList.size()==0){
           throw new Exception("成本子表配置查出没有符合得数据");
       }
        List<BdAccperiodmonthVo> bdAccperiodmonthVoList = commonCostingMapper.getByStatus();
        if (bdAccperiodmonthVoList.size() != 1) {
            throw new Exception("会计月份查出多条或没有符合得数据");
        }
        if (bdAccperiodmonthVoList.get(0).getBeginDate() == null || bdAccperiodmonthVoList.get(0).getEndDate() == null) {
            throw new Exception("会计月份开始时间结束日期未设置");
        }
        this.thread(costConfig, bdAccperiodmonthVoList.get(0),costConfigProductList);
    }

    //线程

    /**
     *
     * @param costConfig
     * @param bdAccperiodmonthVo
     * @param costConfigProductList
     * @throws Exception
     */
    public void thread(CostConfig costConfig, BdAccperiodmonthVo bdAccperiodmonthVo, List<CostConfigProductVo> costConfigProductList) throws Exception {
         //sql server 不支持ifnull  数据库默认0
        //List<MonthlyCostReportItemVo> monthlyCostReportItemVos = monthlyCostReportMapper.getByPeriodId(costConfig.getType().toString(), bdAccperiodmonthVo.getId());
        List<MonthlyCostReportItemVo> monthlyCostReportItemVos = monthlyCostReportMapper.getByModelPeriodId(costConfig.getType().toString(), bdAccperiodmonthVo.getId());
        try {
            ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 1, TimeUnit.SECONDS, new LinkedBlockingQueue());
            int listSize = monthlyCostReportItemVos.size();
            int fetchSize = 1000; //900条执行一IC  in orcale最大查询1000
            for (int i = 0; i < monthlyCostReportItemVos.size(); i += fetchSize) {
                try {
                    if (i + fetchSize > listSize) {        //作用为toIndex最后没有100条数据则剩余几条newList中就装几条
                        fetchSize = listSize - i;
                    }
                    List<MonthlyCostReportItemVo> list = monthlyCostReportItemVos.subList(i, i + fetchSize);
                    if (CollectionUtils.isEmpty(list)) {
                        continue;
                    }
                    executor.submit(() -> {
                        try {
                            this.threadItem(list, costConfig, bdAccperiodmonthVo,costConfigProductList);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    });
                } catch (Exception e) {
                    log.info("处理失败 ", e);
                }
            }
            executor.shutdown();
            while (true) {
                if (executor.isTerminated()) {
                    break;
                }
                Thread.sleep(200);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     *
     * @param list
     * @param costConfig
     * @param bdAccperiodmonthVo
     * @param costConfigProductList
     * @throws Exception
     */
    private void threadItem(List<MonthlyCostReportItemVo> list, CostConfig costConfig, BdAccperiodmonthVo bdAccperiodmonthVo, List<CostConfigProductVo> costConfigProductList) throws Exception {
         List<MonthlyVo> monthlyVoList=new ArrayList<>();
        for (MonthlyCostReportItemVo monthlyCostReportItemVo : list) {
            String sql= this.selectsql(costConfig,monthlyCostReportItemVo,bdAccperiodmonthVo);
            StockInMonthlyVo stockInMonthlyVo = commonCostingMapper.selectSql(sql);
            BigDecimal sumAmount = new BigDecimal(0);
            Integer sumCount = 0;
            if (stockInMonthlyVo == null) {
                sumAmount = monthlyCostReportItemVo.getBeginAmount();
                sumCount = monthlyCostReportItemVo.getBeginQty();
            } else {
                //如果期初金额 0 直接直接入库金额÷入库数量
                if (monthlyCostReportItemVo.getBeginAmount().compareTo(BigDecimal.ZERO) == 0) {
                    sumAmount = stockInMonthlyVo.getAmount();
                    sumCount = stockInMonthlyVo.getQty();
                } else {
                    sumAmount = monthlyCostReportItemVo.getBeginAmount().add(stockInMonthlyVo.getAmount());
                    sumCount = stockInMonthlyVo.getQty() + monthlyCostReportItemVo.getBeginQty();
                }
            }
            // 更新出库单  销售出库单 根据过滤得条件 筛选
            MonthlyVo monthlyVo = new MonthlyVo();
            monthlyVo.setOrgId(monthlyCostReportItemVo.getOrgId());
            monthlyVo.setItemId(monthlyCostReportItemVo.getItemId());
            monthlyVo.setBeginDate(bdAccperiodmonthVo.getBeginDate());
            monthlyVo.setEndDate(bdAccperiodmonthVo.getEndDate());
            monthlyVo.setShopId(monthlyCostReportItemVo.getShopId());
            monthlyVo.setStockId(monthlyCostReportItemVo.getStockId());
            if (sumCount == 0) {
                continue;
            }
            //计算 当期加权平均价
            BigDecimal weightedAverage = sumAmount.divide(BigDecimal.valueOf(sumCount), 2, BigDecimal.ROUND_HALF_UP);
            monthlyVo.setAmount(weightedAverage);
           this.updateSql(costConfig,monthlyVo,costConfigProductList);
        }

    }
    private String selectsql(CostConfig costConfig, MonthlyCostReportItemVo monthlyCostReportItemVo, BdAccperiodmonthVo bdAccperiodmonthVo) throws Exception {
        String sql = "";
        //根据维度(1 - 组织+物料; 2 - 组织+仓库+物料; 3 - 组织+店铺+物料; )
        switch (costConfig.getType()) {
            case 1:
                sql=String.format(costConfig.getSelectSql(),DateUtils.getTimesBeginStr(bdAccperiodmonthVo.getBeginDate()),DateUtils.getTimesEndStr(bdAccperiodmonthVo.getEndDate()),monthlyCostReportItemVo.getOrgId(),monthlyCostReportItemVo.getItemId());
                return sql;
            case 2:
                sql=String.format(costConfig.getSelectSql(),DateUtils.getTimesBeginStr(bdAccperiodmonthVo.getBeginDate()),DateUtils.getTimesEndStr(bdAccperiodmonthVo.getEndDate()),monthlyCostReportItemVo.getOrgId(),monthlyCostReportItemVo.getStockId(),monthlyCostReportItemVo.getItemId());
                return sql;
            case 3:
                sql=String.format(costConfig.getSelectSql(),DateUtils.getTimesBeginStr(bdAccperiodmonthVo.getBeginDate()),DateUtils.getTimesEndStr(bdAccperiodmonthVo.getEndDate()),monthlyCostReportItemVo.getOrgId(),monthlyCostReportItemVo.getShopId(),monthlyCostReportItemVo.getItemId());
                return sql;
            default:
                throw new Exception("对应模式不符合");
        }
    }
    private void updateSql(CostConfig costConfig, MonthlyVo monthlyVo, List<CostConfigProductVo> costConfigProductList) throws Exception {
        for (CostConfigProductVo costConfigProductVo : costConfigProductList) {
            String sql = "";
            //根据维度(1 - 组织+物料; 2 - 组织+仓库+物料; 3 - 组织+店铺+物料; )
            switch (costConfig.getType()) {
                case 1:
                    sql=String.format(costConfigProductVo.getUpdateSql(),monthlyVo.getAmount(), DateUtils.getTimesBeginStr( monthlyVo.getBeginDate()),DateUtils.getTimesEndStr(monthlyVo.getEndDate()),monthlyVo.getOrgId(),monthlyVo.getItemId());
                    break;
                case 2:
                    sql=String.format(costConfigProductVo.getUpdateSql(),monthlyVo.getAmount(), DateUtils.getTimesBeginStr( monthlyVo.getBeginDate()),DateUtils.getTimesEndStr(monthlyVo.getEndDate()),monthlyVo.getOrgId(),monthlyVo.getStockId(),monthlyVo.getItemId());
                    break;
                case 3:
                    sql=String.format(costConfigProductVo.getUpdateSql(),monthlyVo.getAmount(),DateUtils.getTimesBeginStr( monthlyVo.getBeginDate()),DateUtils.getTimesEndStr(monthlyVo.getEndDate()),monthlyVo.getOrgId(),monthlyVo.getShopId(),monthlyVo.getItemId());
                    break;
                default:
                    throw new Exception("对应模式不符合");
            }
            commonCostingMapper.updateSql(sql);
        }
    }
}